package com.starbaba.core.spring.interceptor;

import java.lang.reflect.Proxy;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.starbaba.core.utils.EhcacheManager;

/**
 * 方法拦截器，拦截查询数据库的方法调用（Spring 配置），优先返回使用缓存，然后才是查数据库
 *
 * @Copyright: Copyright (c) 2006
 * @Company: Revenco Tech Ltd.
 * @anthor chenminhui<chenminhui@revenco.com>
 * @since 2013-10-31 下午02:58:48
 * @version V1.0
 */
public class MethodCacheInterceptor implements MethodInterceptor {
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());

	private CacheManager cacheManager;
	
	public void setCacheManager(CacheManager cacheManager) {
		this.cacheManager = cacheManager;
	}

	/** 
	 * 拦截方法调用，优先使用缓存，否则再调用Bean方法来查询数据库，然后再放到缓存中
	 * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
	 */
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		logger.info("拦截方法[" + invocation.getMethod() + "]调用");
		String targetName = invocation.getThis().getClass().getName();
		if(Proxy.isProxyClass(invocation.getThis().getClass())) {
			//若是代理类实例，则分析出给被代理的原始类
			targetName = StringUtils.substringBefore(ObjectUtils.toString(invocation.getThis()), "@");
		}
		
		String methodName = invocation.getMethod().getName();
		Object[] arguments = invocation.getArguments();
		Object result = null;
//		logger.info("查找Cache名称：" + targetName);
		Cache cache = cacheManager.getCache(targetName);
		if(cache == null) {
			logger.error("Cache名称" + targetName + "没有在配置文件中配置，不能使用缓存");
			return invocation.proceed();
		}
		
		String cacheKey = getCacheKey(targetName, methodName, arguments);
//		synchronized (this) {
			Element element = cache.get(cacheKey);
			
			if (element == null || element.getObjectValue() == null) {
				// 调用实际的方法
				result = invocation.proceed();
				
				logger.info("加入到缓存： " + cacheKey + " --> [" + cache.getName() + "]");
				element = new Element(cacheKey, result);
				cache.put(element);
			} else {
				logger.info("使用缓存： " + cacheKey + " <-- [" + cache.getName() + "]");
				result = element.getObjectValue();
			}
//		}
		
		return result;
	}

	/**
	 * 返回具体的方法全路径名称
	 * 
	 * @param classClass 类全路径名
	 * @param methodName 方法名
	 * @param arguments 参数列表
	 * @return String 缓存Key
	 *
	 * @Copyright: Copyright (c) 2006
	 * @Company: Revenco Tech Ltd.
	 * @anthor chenminhui<chenminhui@revenco.com>
	 * @since 2013-10-31 下午03:08:53
	 * @version V1.0
	 */
	public static String getCacheKey(String classClass, String methodName, Object[] arguments) {
		StringBuffer sb = new StringBuffer();
		sb.append(classClass).append(".").append(methodName);
		if ((arguments != null) && (arguments.length != 0)) {
			for (int i = 0; i < arguments.length; i++) {
				sb.append(".").append(arguments[i]);
			}
		}
		return sb.toString();
	}
	
	/**
	 * 返回缓存值，若没有缓存则返回null
	 * 
	 * @param classClass 类全路径名
	 * @param methodName 方法名
	 * @param arguments 参数列表
	 * @return Object 缓存值
	 *
	 * @Copyright: Copyright (c) 2006
	 * @Company: Revenco Tech Ltd.
	 * @anthor chenminhui<chenminhui@revenco.com>
	 * @since 2014-10-8 下午03:22:23
	 * @version V1.0
	 */
	public static Object getCacheValue(String classClass, String methodName, Object[] arguments) {
		Cache cache = EhcacheManager.getCache(classClass);
		String cacheKey = getCacheKey(classClass, methodName, arguments);
		if(cache != null) {
			Element cacheEle = cache.get(cacheKey);
			if(cacheEle != null) {
				return cacheEle.getObjectValue();
			}
		}
		
		return null;
	}
	
	/** 测试入口
	 * @param args
	 *
	 * @Copyright: Copyright (c) 2006
	 * @Company: Revenco Tech Ltd.
	 * @anthor chenminhui<chenminhui@revenco.com>
	 * @since 2013-10-31 下午02:58:38
	 * @version V1.0
	 */
	public static void main(String[] args) {
		
	}

}
